﻿using System;

namespace SeizyUtils.Common.Utilities
{
    /// <summary>
    /// 型に関する便利クラスをまとめたユーティリティクラスです。
    /// このクラスは、IBeanのデータバインドフレームワークにとって
    /// 重要な役割を持ちます。
    /// </summary>
    class TypeUtils
    {
        private TypeUtils(){}


        /// <summary>
        /// 値の型を強制的にTypeに合わせて変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object castType(object value, Type type)
        {

            object result = null;
            if (type == typeof(string))
            {
                result = castString(value);
            }
            else if (type == typeof (int))
            {
                result = castInt(value);
            }
            else if (type == typeof (long))
            {
                result = castLong(value);
            }
            else if (type == typeof(decimal))
            {
                result = castDecimal(value);
            }
            else if(type == typeof(DateTime))
            {
                result = castDate(value);
            }
            else if (type == typeof(int?))
            {
                result = castIntNull(value);
            }
            else if (type == typeof(long?))
            {
                result = castLongNull(value);
            }
            else if (type == typeof(decimal?))
            {
                result = castDecimalNull(value);
            }
            else if (type == typeof(DateTime?))
            {
                result = castDateNull(value);
            }
            else
            {
                throw new ApplicationException("TypeUtils.castType()に無い型["+ type.ToString() +"]を変換しようとしました。\n型定義の分岐を増やしてください。");
            }
            return result;

        }


        /// <summary>
        /// Objectを文字列に変換します。
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string castString(object obj)
        {
            if (obj == null)
            {
                return null;
            }
            if (obj.GetType() == typeof (DateTime))
            {
                return ((DateTime)obj).ToString("yyyy-MM-dd HH:mm:ss");
            }
            else if (obj.GetType() == typeof(DateTime?))
            {
                return ((DateTime?)obj).Value.ToString("yyyy-MM-dd HH:mm:ss");
            }
            return obj.ToString();
        }


        /// <summary>
        /// int型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int castInt(object value)
        {
            int result = 0;

            Type valueType = value.GetType();
            if (valueType == typeof(string))
            {
                result = int.Parse((string)value);
            }
            else if(valueType == typeof(int))
            {
                result = (int)value;
            }
            return result;

        }

        /// <summary>
        /// int?型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int? castIntNull(object value)
        {
            int? result = null;

            Type valueType = value.GetType();
            if (valueType == typeof(string))
            {
                if (string.IsNullOrEmpty((string)value))
                {
                    return null;
                }
                result = int.Parse((string)value);
            }
            else if (valueType == typeof(int))
            {
                result = (int)value;
            }
            else if (valueType == typeof(int?))
            {
                result = (int?)value;
            }
            return result;

        }

        /// <summary>
        /// long型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static long castLong(object value)
        {
            long result = 0;

            Type valueType = value.GetType();
            if (valueType == typeof(string))
            {
                result = long.Parse((string)value);
            }
            else if (valueType == typeof(int))
            {
                result = (int)value;
            }else if (valueType == typeof (long))
            {
                result = (long) value;
            }
            return result;
        }

        /// <summary>
        /// long?型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static long? castLongNull(object value)
        {
            long? result = null;

            Type valueType = value.GetType();
            if (valueType == typeof(string))
            {
                if (string.IsNullOrEmpty((string)value))
                {
                    return null;
                }
                result = long.Parse((string)value);
            }
            else if (valueType == typeof(long))
            {
                result = (long)value;
            }
            else if (valueType == typeof(long?))
            {
                result = (long?)value;
            }
            return result;

        }

        /// <summary>
        /// decimal型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal castDecimal(object value)
        {
            decimal result = 0;

            Type valueType = value.GetType();
            if (valueType == typeof(string))
            {
                result = decimal.Parse((string)value);
            }
            else if (valueType == typeof(decimal))
            {
                result = (decimal)value;
            }
            return result;

        }

        /// <summary>
        /// decimal?型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal? castDecimalNull(object value)
        {
            decimal? result = null;

            Type valueType = value.GetType();
            if (valueType == typeof(string))
            {
                if (string.IsNullOrEmpty((string)value))
                {
                    return null;
                }
                result = decimal.Parse((string)value);
            }
            else if (valueType == typeof(decimal))
            {
                result = (decimal)value;
            }
            else if (valueType == typeof(decimal?))
            {
                result = (decimal?)value;
            }
            return result;

        }

        /// <summary>
        /// 日付け型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static DateTime castDate(object value)
        {
            return DateTime.Parse(value.ToString());
        }

        /// <summary>
        /// 日付け型に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static DateTime? castDateNull(object value)
        {
            if (value == null || (value.GetType() == typeof(string) && string.IsNullOrEmpty((string)value)))
            {
                return null;
            }
            return DateTime.Parse(value.ToString());
        }


        /// <summary>
        /// valueを文字列に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string toString(object value)
        {
            string result = "";
            if (value == null)
            {
                return result;
            }
            Type type = value.GetType();
            if (type == typeof(string))
            {
                result = (string) value;
            }
            else if (type == typeof(int))
            {
                result = value.ToString();
            }
            else if (type == typeof(long))
            {
                result = value.ToString();

            }
            else if (type == typeof(DateTime))
            {
                // DBのフォーマットに変換します。= YYYY-MM-DD HH:MM:SS
                result = ((DateTime)value).ToString("gyyyy-MM-dd hh:mm:ss");
            }
            else
            {
                throw new ApplicationException("TypeUtils.castType()に無い型を変換しようとしました。\n型定義の分岐を増やしてください。");
            }
            return result;
        }
    }
}
